package cn.leedsoft.and.crimeintent.model.photo_gallery;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.support.v4.util.LruCache;
import android.util.Log;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;

import java.util.List;
import java.util.Map;

/**
 * Created by leeds on 2016/8/24 20:05.
 */
public class PicDownloader<Token> extends HandlerThread {
    private static final String TAG = "PicDownloader";
    private static final int MESSAGE_DOWNLOAD = 0;
    private static final int MESSAGE_PRELOAD = 1;
    private Handler mHandler;
    private Handler mResponseHandler;//成员 导航 member（m）
    private Map<Token, String> requestMap = Maps.newConcurrentMap();//待处理的token
    private Listener mListener;
    private PhotoHttpFetcher mPhotoHttpFetcher = new PhotoHttpFetcher();
    private LruCache<String, Bitmap> mBitmapLruCache = new LruCache<String, Bitmap>(30);

    public interface Listener<Token> {//回调接口：声明接口、传递实现（传递给当前类实现该接口的引用）

        void onPicDownloaded(Token token, Bitmap bitmap, GalleryItem item);//目的，是让逻辑，更加模块化。
    }

    @Override
    protected void onLooperPrepared() {//在looper prepared前，初始化handler
        mHandler = new Handler() {//handler 默认绑定当前 handlerThread 的looper。。主线程也是一种handler thread。
            @Override
            public void handleMessage(Message msg) {//handler具体处理过程
                if (msg.what == MESSAGE_DOWNLOAD) {
                    ImmutableMap params = (ImmutableMap) msg.obj;
                    handleRequest(params);
                }
                if (msg.what == MESSAGE_PRELOAD) {
                    String url = (String) msg.obj;
                    obtainBitmap(url);
                }
            }
        };
    }

    private void handleRequest(ImmutableMap params) {//封装方法，并非一定是为了代码复用。还有一个目的，是让逻辑，更加模块化。
        final Token token = (Token) params.get("token");
        final GalleryItem item = (GalleryItem) params.get("item");
        final String url = requestMap.get(token);
        if (url == null) return;
        final Bitmap bitmap = obtainBitmap(url);
        mResponseHandler.post(new Runnable() {
            @Override
            public void run() {//处理完成，向主线程发送message。。。。通过传递handler，获得向绑定looper中添加message的能力
                if (requestMap.get(token) != url) return;//GridView会循环使用它的视图.
//                PicDownloader完成Bitmap下载后， GridView可能已经循环使用了ImageView，并继续请求一个不同的URL
                requestMap.remove(token);
                mListener.onPicDownloaded(token, bitmap, item);//UI更新 必须在主线程
            }
        });

    }

    private Bitmap obtainBitmap(String url) {//缓存
        if(url == null) return null;
        Bitmap bitmap = mBitmapLruCache.get(url);
        if (bitmap == null) {

            byte[] bitmapBytes = mPhotoHttpFetcher.fetchBytes(url);
            if (bitmapBytes == null) {
                Log.e(TAG, "Error! picture download failed : " + url);
                return null;
            }
            bitmap = BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.length);
            if(bitmap == null) {
                Log.e(TAG, "Error! picture download failed : " + url);
                return null;
            }
            mBitmapLruCache.put(url, bitmap);
            Log.i(TAG, "bitmap downloaded and cached :" + url);
        } else {
            Log.i(TAG, "retrieve the picture from CACHE :" + url);
        }
        return bitmap;
    }

    public PicDownloader(Handler handler, Listener<Token> listener) {
        super(TAG);
        mResponseHandler = handler;
        mListener = listener;
    }

    public void queuePic(Token token, GalleryItem item, List<String> preloadUrls) {//向PicDownloader Handler Thread，发送message
        Log.i(TAG, "to retrieve a picture :" + item.getUri());//养成记录日志的习惯：关于逻辑中【事件】的记录。比如：图片开始下载、图片下载完成、图片下载出错
        requestMap.put(token, item.getUri());

        mHandler.obtainMessage(MESSAGE_DOWNLOAD, ImmutableMap.of("token", token, "item", item))//创建message （设置了what、obj、target handler）
                .sendToTarget();//Pushes a message onto the end of the message queue...

        for (int i = 0; i < preloadUrls.size(); i++) {//预加载
            if(mBitmapLruCache.get(preloadUrls.get(i)) == null) {
                mHandler.obtainMessage(MESSAGE_PRELOAD, preloadUrls.get(i))
                        .sendToTarget();
            }
        }

    }
}
